#define
宏定义#define
是一条预编译指令, 编译器在编译阶段前期会将所有使用到宏的地方简单地进行替换.
在预处理器里进行文本替换,没有类型,不做任何类型检查,编译器可以对相同的字符串进行优化。只保存一份到 .rodata 段。甚至有相同后缀的字符串也可以优化,你可以用GCC 编译测试,”Hello world” 与 “world” 两个字符串,只存储前面一个。取的时候只需要给前面和中间的地址,如果是整形、浮点型会有多份拷贝,但这些数写在指令中。占的只是代码段而已,大量用宏会导致二进制文件变大
但#define
可以使用类型定义,比如
#define MY_INT_CONSTANT ((int)123)
const
const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝
如果在一个指定单一类里声明常量,在.m 文件顶端用 static const 声明
static NSString *const MyThingNotificationKey = @"MyThingNotificationKey";
如果常量属于一个类,但又要其他类可以访问,在头文件将其声明为 extern ,在.m文件定义
//.h
extern NSString *const MyThingNotificationKey;
//.m
NSString *const MyThingNotificationKey = @"MyThingNotificationKey";
如果它们是全局的常量,在头文件声明,并在相应模块里定义。
只有公有的常量才需要添加命名空间作为前缀。尽管实现文件中私有常量的命名可以遵循另外一种模式,你仍旧可以遵循这个规则。
enum
enum拥有define和const两者的优点,不过enum只能定义整型常量。
如何选择
尽量选择使用const,因为编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率比宏定义要高。
相反,define占据更多的内存空间,因为它只是文字替换,导致存在过多的拷贝。当然这一点是对于一般类型的常量来说的。对于int型常量,引用const的地方拿到的是内存地址,地址数据和int差不多,所以内存上应该不会有太大区别。
另外,const对编译器和调试器来说更加友好。这一点可以作为一个很重要的参考。
记录比较粗略,只是简单整理一下网友讨论,这里用到的具体的语法还是要自己去研究,比如const int 和 int const的区别等。
update at May 20
关于命名规范
常量名(如宏定义、枚举、静态局部变量等)应该以小写字母k
开头,使用驼峰格式分隔单词,如:kInvalidHandle
,kWritePerm
。参考
苹果官方文档介绍编码规范提到常量部分:链接
- 对于一组相关的整型常量,应使用枚举类型
- 使用const创建浮点型常量。如果这个常量与其他常量没有关联,也可以使用const创建整型常量,否则使用枚举
- 通常来说,不要使用#define创建常量,使用上两条
update at June 28
这里提到枚举类型,就在这里补充点内容吧。
Apple 文档: Adopting Modern Objective-C
对于 Objective-C 来说,枚举类型建议使用 NS_ENUM
和 NS_OPTIONS
宏。因为它们有更强大的类型检查和代码补全。此外,这个语法提供枚举的方式也兼容旧编译器,当然新编译器可以更好的解析出其隐含的类型信息。
- 使用
NS_ENUM
宏定义枚举数据,其内容的值都是互斥的:
typedef NS_ENUM(NSInteger, UITableViewCellStyle) {
UITableViewCellStyleDefault,
UITableViewCellStyleValue1,
UITableViewCellStyleValue2,
UITableViewCellStyleSubtitle
};
NS_ENUM
宏不仅定义了枚举的名称(UITableViewCellStyle),还定义了类型(NSInteger),一般来说枚举的类型是 NSInteger
。
NS_OPTIONS
宏定义选项类型,定义一组可以组合的位掩码值:
typedef NS_OPTIONS(NSUInteger, UIViewAutoresizing) {
UIViewAutoresizingNone = 0,
UIViewAutoresizingFlexibleLeftMargin = 1 << 0,
UIViewAutoresizingFlexibleWidth = 1 << 1,
UIViewAutoresizingFlexibleRightMargin = 1 << 2,
UIViewAutoresizingFlexibleTopMargin = 1 << 3,
UIViewAutoresizingFlexibleHeight = 1 << 4,
UIViewAutoresizingFlexibleBottomMargin = 1 << 5
};
NS_OPTIONS
的定义也包含名称和类型。一般来说选项的类型是 NSUInteger
。
选项和枚举的差别是枚举只能出现一项,选项可以出现一项或几项,所以选项使用位运算
#define vs const in Objective-C
What is the best way to create constants in Objective-C